/*
The MIT License (MIT)

Copyright (c) 2013 Mike Dapiran, Brian May, Richard Pospesel, and Bert Wierenga

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software 
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once

#include "Hogshead.Common.h"

#include "Interfaces\IHObject.h"
#include "Interfaces\IGUIObject.h"
#include "Interfaces\IComponent.h"
#include "Interfaces\IMessageReceiver.h"
#include "Interfaces\IMessage.h"
#include "Transform2D.h"


namespace Hogshead
{
	namespace Core
	{
		class Scene;

		/**
		* GUIPanel is a container class for all IGUIObject and all GUIPanel objects. This class is closely
		* modeled after the GameObject container class, as it shares many similar properties to it. GUIPanels
		* created will have a defined depth, which is used to determine which IGUIObjects will be rendered
		* first. Positive to negative equates to front to back. This class also contains a Transform2D object
		* and a parent GUIPanel object. Transform2D identifies where in screen space the panel is located,
		* and since GUIPanels can be hierarchically organized a reference to the parent is necessary.
		*
		* @see IGUIObject
		* @see Transform2D
		* @see IHObject
		* @see GameObject
		*
		* @author Ben Dapkiewicz
		*/
		class GUIPanel : public IHObject, public IMessageReceiver
		{
			HObjectH(Hogshead::Core::GUIPanel)

		public:
			/**
			* Default Constructor; Sets the parent to NULL and the name to a null string.
			*/
			GUIPanel(void);

			/**
			* Destructor; Does nothing.
			*/
			~GUIPanel(void);

			/**
			* assignment operator; Copies the data in the other GUIPanel's Transform2D, Components,
			* and child GUIPanels.
			*
			* @param other The GUIPanel to copy from.
			*/
			GUIPanel& operator=(const GUIPanel& other);

			/**
			* clone method; This method is called to get a new instance of a GUIPanel that is a copy
			* of this GUIPanel. The clone will have the same name, Transform2D data, copies of all
			* the same Components with mirrored data, and clones of all the same child GUIPanels.
			*/
			GUIPanel* clone() const;


			/**
			* initialize method; Called at initialization time. Used to call initialize on our Transform2D,
			* IGUIObject Components, and child GUIPanel objects.
			*/
			void initialize();

			/**
			* update method; Called during the update loop. Used to update all Components then all child GUIPanels.
			*
			* @param in_gt The GameTimer for the running game which stores time information.
			*/
			void update(const GameTimer& in_gt);


			/**
			* getTransform2D method; Returns a reference to this GUIPanel's Transform2D.
			*/
			Transform2D& getTransform2D();

			/**
			* name method; Returns the name of this GUIPanel.
			*/
			const String& name() const;

			GUIPanel* getChildPanelByName(const String& in_name);

			/**
			* guiPanelCount method; Returns the number of children GUIPanel objects.
			*/
			int guiPanelCount() const;

			/**
			* getChildGUIPanel method; Returns the child GUIPanel object at the specified index.
			*
			* @param in_index The index to grab from.
			*/
			GUIPanel* getChildGUIPanel(int in_index);
			
			/**
			* addChildPanel method; Adds a new child GUIPanel to this GUIPanel.
			*
			* @param in_panel The child GUIPanel to be added.
			*/
			void addChildPanel(GUIPanel* in_panel);


			/**
			* guiObjectCount method; Returns the number of IGUIObject components.
			*/
			int guiObjectCount() const;

			/**
			* getGUIObject method; Returns the IGUIObject component at the specified index.
			*
			* @param in_index The index to grab from.
			*/
			IGUIObject* getGUIObject(int in_index);

			/**
			* addGUIObject method; Adds a new IGUIObject component to this GUIPanel.
			*
			* @param in_gui_object The IGUIObject component to be added.
			*/
			void addGUIObject(IGUIObject* in_gui_object);


			/**
			* getParentPanel method; Returns this GUIPanel's parent GUIPanel.
			*/
			GUIPanel* getParentPanel();

			/**
			* setParentPanel method; Sets this GUIPanel's parent GUIPanel.
			*
			* @param in_panel The GUIPanel to be set.
			*/
			void setParentPanel(GUIPanel* in_panel);

			/**
			* getScene method; Returns this GUIPanel's Scene.
			*/
			Scene* getScene();

			/**
			* setScene method; Sets this GUIPanel's Scene.
			*
			* @param in_scene The Scene to be set.
			*/
			void setScene(Scene* in_scene);


			/**
			* readXML method; This method is called to load this GUIPanel in a Scene file.
			*
			* @param in_xml A bock of XML stored in a string that should have a root element of this GUIPanel.
			* @param in_owner The Scene that this GUIPanel belongs to.
			*
			* @return Returns a pointer to this GUIPanel.
			*/
			GUIPanel* readXML(const String& in_xml, IHObject* in_owner);


			/**
			* getGUIObjectOfType method; Returns the first Component found on this GUIPanel of
			* the type passed through the template. If no Component of the type is found, NULL
			* is returned.
			*/
			template<typename T> T* getGUIObjectOfType()
			{
				for(int i = 0; i < _gui_objects.size(); i++)
				{
					if(_gui_objects[i]->is<T>())
					{
						return (T*)_gui_objects[i];
					}
				}
				return NULL;
			}

			/**
			* getGUIObjectsOfType method; Returns an Array1D of all Components found on this
			* GUIPanel of the type passed through the template. This will return an empty array
			* if no Components of the specified type are found.
			*/
			template<typename T> Array1D<T*> getGUIObjectsOfType()
			{
				int count = 0;
				for(int i = 0; i < _gui_objects.size(); i++)
				{
					if(_gui_objects[i]->is<T>())
					{
						count++;
					}
				}
				Array1D<T*> result(count);

				int index = 0;
				for(int i = 0; i < _gui_objects.size(); i++)
				{
					if(_gui_objects[i]->is<T>())
					{
						result(index++) = (T*)_gui_objects[i];
					}
				}

				return result;
			}

			void setActivity(bool in_activity); 
			bool getActivity();
		private:
			friend class IGUIObject;
			friend class IComponent;
			friend class Scene;
			friend class Transform2D;

			/**
			* handle_panel_transform_message method; This method handles PanelTransformMessages, which
			* accept a translation, rotation, and scale to apply to the GUIPanel.
			*
			* @param IMessageReceiver* The message receiver.
			* @param IMessage* The message.
			*/
			static void handle_panel_transform_message(IMessageReceiver*, IMessage*);

			/**
			* copy method; This will copy information from another GUIPanel into this GUIPanel.
			*
			* @param in_other The GUIPanel to be copied from.
			*/
			GUIPanel& copy(const GUIPanel& in_other);

			//the name of the panel
			String _name;

			//the parent GUIPanel
			GUIPanel* _parent_panel;
			//the parent scene
			Scene* _parent_scene;

			//containers for child GUIPanels and IGUIObjects
			Vector<GUIPanel*> _child_panels;
			Vector<IGUIObject*> _gui_objects;

			//transform to store the location in screen space
			Transform2D _transform2D;

			//depth for rendering
			int depth;

			bool _active;
		};
	}
}